package com.wsg.dep.queue;

import com.wsg.dep.core.event.EventFactory;
import com.wsg.dep.util.UnSafeUtil;
import com.wsg.dep.util.Utils;
import sun.misc.Unsafe;

import java.util.concurrent.ForkJoinPool;
import java.util.stream.IntStream;

/**
 * @className: BaseRingQueue
 * @author: 承泽
 * @date: 2025/3/17 20:08
 * @description: 高性能无锁环形队列实现
 * <p>
 * 核心设计：
 * 1. 缓存行填充：通过前后填充无效元素，避免伪共享（False Sharing）
 * 2. 无锁设计：利用CAS和内存屏障实现线程安全
 * 3. 位运算优化：通过掩码计算替代取模运算，提升索引计算效率
 * 4. 内存预分配：初始化时预创建所有事件对象，减少GC压力
 */
public class BaseRingQueue<E> {
    // ============================== 静态常量 ==============================
    /**
     * 现代CPU缓存行大小（单位：字节），用于计算填充元素数量
     */
    private static final int CACHE_LINE_SIZE = 64;

    /**
     * 每个缓存行可容纳的元素数量（根据数组元素大小动态计算）
     * Object数组元素在32位系统占4字节，64位系统占8字节
     */
    private static final int BUFFER_PAD;

    /**
     * 存储元素的数组在内存中的基础偏移地址
     * 计算方式：数组起始地址 + 前填充元素的总字节数
     */
    private static final long REF_ARRAY_BASE;

    /**
     * 数组元素偏移量的位移计算基数
     * 32位系统：4字节元素 => 2^2，位移数为2
     * 64位系统：8字节元素 => 2^3，位移数为3
     */
    private static final int REF_ELEMENT_SHIFT;

    /**
     * Unsafe实例，用于执行底层内存操作
     */
    private static final Unsafe UNSAFE = UnSafeUtil.getUnsafe();

    // ============================== 静态初始化 ==============================
    static {
        // 获取Object数组的元素大小（4或8字节）
        final int scale = UNSAFE.arrayIndexScale(Object[].class);
        validateScale(scale); // 参数合法性校验

        // 计算元素偏移量的位移数（32位系统为2，64位系统为3）
        REF_ELEMENT_SHIFT = (scale == 4) ? 2 : 3;

        // 计算缓存行填充元素数量（例如64字节缓存行 / 8字节元素 = 8个填充元素）
        BUFFER_PAD = CACHE_LINE_SIZE / scale;

        // 计算有效元素的起始内存地址：
        // 数组基础偏移（通常16字节） + 前填充元素的字节总数
        REF_ARRAY_BASE = UNSAFE.arrayBaseOffset(Object[].class) + (BUFFER_PAD << REF_ELEMENT_SHIFT);
    }

    // ============================== 实例变量 ==============================
    /**
     * 索引掩码，用于快速计算环形索引（替代取模运算）
     * 当bufferSize为2^n时，(sequence & indexMask) 等效于 sequence % bufferSize
     */
    private final long indexMask;

    /**
     * 存储元素的数组，结构为：
     * [无效元素...BUFFER_PAD个 | 有效元素...bufferSize个 | 无效元素...BUFFER_PAD个]
     * 前后填充无效元素以避免伪共享
     */
    private final Object[] entries;

    /**
     * 环形队列容量，必须为2的幂次方
     */
    protected final int bufferSize;

    // ============================== 构造方法 ==============================

    /**
     * 构造环形队列
     *
     * @param eventFactory 事件对象工厂（必须是线程安全的）
     * @param bufferSize   队列容量（必须为2的幂次方）
     */
    protected BaseRingQueue(EventFactory<E> eventFactory, int bufferSize) {
        // 校验bufferSize合法性（必须是2的幂次方）
        Utils.bufferSizeCheck(bufferSize);

        this.bufferSize = bufferSize;
        this.indexMask = bufferSize - 1; // 生成掩码

        // 初始化存储数组：总长度 = 有效元素 + 前后填充元素
        this.entries = new Object[bufferSize + 2 * BUFFER_PAD];

        // 预分配事件对象（填充中间的有效区域）
        fill(eventFactory);
    }

    // ============================== 核心方法 ==============================

    /**
     * 预填充事件对象到数组的有效区域
     * 使用并行流加速初始化过程（需要确保eventFactory线程安全）
     */
    private void fill(EventFactory<E> eventFactory) {
        ForkJoinPool pool = new ForkJoinPool();
        pool.submit(() ->
                IntStream.range(0, bufferSize)
                        .parallel() // 并行初始化
                        .forEach(i -> {
                            // 在有效区域（中间段）填充事件对象
                            entries[BUFFER_PAD + i] = eventFactory.newInstance();
                        })
        ).join();
    }

    /**
     * 根据序列号获取队列元素（线程安全）
     *
     * @param cursor 元素序列号（单调递增）
     * @return 对应位置的元素
     */
    public final E get(long cursor) {
        // 插入读屏障，确保之前的所有读操作完成
        UNSAFE.loadFence();

        // 计算实际存储位置（两步操作）：
        // 1. cursor & indexMask => 环形索引计算（替代取模）
        // 2. REF_ARRAY_BASE + 计算结果 => 跳过前填充区域
        // 使用volatile语义读取对象，保证内存可见性
        E value = (E) UNSAFE.getObjectVolatile(entries,
                REF_ARRAY_BASE + ((cursor & indexMask)<< REF_ELEMENT_SHIFT));

        // 再次插入读屏障，确保后续操作可见性
        UNSAFE.loadFence();
        return value;
    }

    /**
     * 获取队列容量
     */
    public final int bufferSize() {
        return bufferSize;
    }

    // ============================== 辅助方法 ==============================

    /**
     * 校验数组元素大小的合法性
     *
     * @param scale 数组元素大小（必须为4或8）
     */
    private static void validateScale(int scale) {
        if (scale != 4 && scale != 8) {
            throw new IllegalStateException("Unsupported array scale: " + scale
                    + " (expected 4 or 8)");
        }
    }

    /**
     * 展示队列的基本情况
     * 可通过此方法看到队列的前后填充情况
     */
    public void showQueue() {
        for (int i = 0; i < this.entries.length; i++) {
            System.out.print(this.entries[i]);
        }
        System.out.println("=======================");
    }
}